package application;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;

import javax.swing.SwingUtilities;

import processes.ProcessDescriptor;
import gui.SkyGui;

/**
 * Wraps SkyGui. Adds options to manipulate with thread. 
 * @author Miroslav Vozabal, Josef Vopalecky
 *
 */
public class Gui extends Application{
	private SkyGui skyGui;
	private PipedInputStream pis;
	private PipedOutputStream pos;
	private Boolean end = false;
	private Core core;
	private ProcessDescriptor consument;
	private Boolean interupt = true;
	private int commPointer = -1;
	
	/**
	 * Gets consumer.
	 * @return
	 */
	public ProcessDescriptor getConsument() {
		return consument;
	}

	/**
	 * Sets consumer.
	 * @param consument
	 */
	public void setConsument(ProcessDescriptor consument) {
		this.consument = consument;
	}

	/**
	 * Constructor.
	 */
	public Gui(){
		skyGui = new SkyGui(this);
		pis = new PipedInputStream();
		pos = new PipedOutputStream();
		setPriority(Thread.MAX_PRIORITY);
	}
	
	@Override
	public void code() {
		while(!end){
			if(pis != null){	
				try {
					if(pis.available() > 0){
							BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(pis));
							try {
								final String text = bufferedReader.readLine();
								if(text != null){
									interupt = false;
									Runnable updateAComponent = new Runnable() {
									    public void run() { skyGui.writeOutputLn(text); }
									};
									SwingUtilities.invokeLater(updateAComponent);
								}
							} catch (IOException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
						}
					} catch (IOException e) {
						
					}				
				
			}
		}
		super.stop();
		
	}
	/**
	 * Gets SkyGui
	 * @return
	 */
	public SkyGui getOsGui() {
		return skyGui;
	}
	
	/**
	 * Gets PipedInputStream.
	 * @return
	 */
	public PipedInputStream getPis() {
		return pis;
	}

	/**
	 * Sets PipeddInputStream.
	 * @param p
	 */
	public void setPis(PipedInputStream p) {
		pis = p;
	}

	/**
	 * Gets PipedOutputStream.
	 * @return
	 */
	public PipedOutputStream getPos() {
		return pos;
	}

	/**
	 * Sets PipedOutputStream.
	 * @param p
	 */
	public void setPos(PipedOutputStream p) {
		pos = p;
	}
	
	/**
	 * Sets core.
	 * @param core
	 */
	public void setCore(Core core){
		this.core = core;
	}
	
	/**
	 * Kills last parent processes (more: class Core).
	 */
	public void killLastParentProcesses(){
		core.killLastParentProcesses();
	}
	
	/**
	 * Writes data to the PipedOutputStream.
	 * @param text for writing
	 */
	public void write(String text){
		if(!text.endsWith("\n")){
			text = text + "\n";
		}
		try {
			pos.write(text.getBytes());
			pos.flush();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	/**
	 * Tests whether the console is ready for communication.
	 * @return status console
	 */
	public Boolean consoleIsRdy(){
		if(skyGui == null){
			return false;
		}
		return true;
	}
	
	/**
	 * Outputs the specified text to the console.
	 * @param text for writing
	 */
	public void writeConsole(final String text){
		Runnable updateAComponent = new Runnable() {
		    public void run() { skyGui.writeOutput(text); }
		};
		SwingUtilities.invokeLater(updateAComponent);
	}
	
	/**
	 * Closes the input from the console or closes the shell.
	 */
	public void endRead(){
		if(interupt == false){
			try {
				pos.close();
				if(consument.getCanRead()){
					consument.setCanRead(false);
				}				
			} catch (IOException e) {
				e.printStackTrace();
			}
			interupt = true;
		}
		else{
			try {
				pos.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			core.closeLastProcess();
		}		
	}
	
	/**
	 * Give input to the console next command.
	 */
	public void nextCommand(){
		commPointer =  commPointer  + 1;
		if(core.sizeOfListComm() > 0){
			commPointer = commPointer % core.sizeOfListComm();
			if(core.sizeOfListComm() > 0){
				Runnable updateAComponent = new Runnable() {
				    public void run() { skyGui.writeInput(core.getCommand(commPointer)); }
				};
				SwingUtilities.invokeLater(updateAComponent);
			}	
		}
	}

	/**
	 * Give input to the console previous command.
	 */
	public void previouslyCommand(){
		commPointer =  commPointer -1;
		if(core.sizeOfListComm() > 0){
			commPointer = commPointer % core.sizeOfListComm();
			if(commPointer < 0){
				commPointer = core.sizeOfListComm() - 1;
			}
			if(core.sizeOfListComm() > 0){
				Runnable updateAComponent = new Runnable() {
				    public void run() { skyGui.writeInput(core.getCommand(commPointer)); }
				};
				SwingUtilities.invokeLater(updateAComponent);
			}
		}
	}
	
}
